Ext.DomHelper = function()
{
	var tempTableEl = null, emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i, tableRe = /^table|tbody|tr|td$/i, confRe = /tag|children|cn|html$/i, tableElRe = /td|tr|tbody/i, cssRe =
	/([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi, endRe = /end/i, pub,
	// kill repeat to save bytes
	afterbegin = 'afterbegin', afterend = 'afterend', beforebegin = 'beforebegin', beforeend = 'beforeend', ts = '<table>', te = '</table>', tbs = ts + '<tbody>', tbe = '</tbody>' + te, trs = tbs + '<tr>', tre = '</tr>' + tbe;

	// private
	function doInsert( el, o, returnElement, pos, sibling, append )
	{
		var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
		return returnElement ? Ext.get(newNode, true) : newNode;
	}

	// 根据specil来构造HTML片段--->>> string
	function createHtml( o )
	{
		var b = '', attr, val, key, cn;

		if( typeof o == "string" )
		{
			b = o;
		}
		else if( Ext.isArray(o) )
		{
			for( var i = 0; i < o.length; i++ )
			{
				if( o[i] )
				{
					b += createHtml(o[i]);
				}
			};
		}
		else
		{
			b += '<' + (o.tag = o.tag || 'div');
			for( attr in o )
			{
				val = o[attr];
				if( !confRe.test(attr) )
				{
					if( typeof val == "object" )
					{
						b += ' ' + attr + '="';
						for( key in val )
						{
							b += key + ':' + val[key] + ';';
						};
						b += '"';
					}
					else
					{
						b += ' ' + (
						{
							cls: 'class',
							htmlFor: 'for'
						}[attr] || attr) + '="' + val + '"';
					}
				}
			};
			// Now either just close the tag or try to add children and close the tag.
			if( emptyTags.test(o.tag) )
			{
				b += '/>';
			}
			else
			{
				b += '>';
				if( (cn = o.children || o.cn) )
				{
					b += createHtml(cn);
				}
				else if( o.html )
				{
					b += o.html;
				}
				b += '</' + o.tag + '>';
			}
		}
		return b;
	}

	function ieTable( depth, s, h, e )
	{
		tempTableEl.innerHTML =
		[
		    s, h, e
		].join('');
		var i = -1, el = tempTableEl, ns;
		while(++i < depth)
		{
			el = el.firstChild;
		}
		// If the result is multiple siblings, then encapsulate them into one fragment.
		if( ns = el.nextSibling )
		{
			var df = document.createDocumentFragment();
			while(el)
			{
				ns = el.nextSibling;
				df.appendChild(el);
				el = ns;
			}
			el = df;
		}
		return el;
	}

	/**
	 * @ignore Nasty code for IE's broken table implementation
	 */
	// 解决IE下Table显示不正常的问题 nasty--->>下流的，肮脏的
	function insertIntoTable( tag, where, el, html )
	{
		var node, before;

		tempTableEl = tempTableEl || document.createElement('div');

		if( tag == 'td' && (where == afterbegin || where == beforeend) || !tableElRe.test(tag) && (where == beforebegin || where == afterend) )
		{
			return;
		}
		before = where == beforebegin ? el : where == afterend ? el.nextSibling : where == afterbegin ? el.firstChild : null;

		if( where == beforebegin || where == afterend )
		{
			el = el.parentNode;
		}

		if( tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin)) )
		{
			node = ieTable(4, trs, html, tre);
		}
		else if( (tag == 'tbody' && (where == beforeend || where == afterbegin)) || (tag == 'tr' && (where == beforebegin || where == afterend)) )
		{
			node = ieTable(3, tbs, html, tbe);
		}
		else
		{
			node = ieTable(2, ts, html, te);
		}
		el.insertBefore(node, before);
		return node;
	}

	/**
	 * @ignore Fix for IE9 createContextualFragment missing method
	 */
	function createContextualFragment( html )
	{
		var div = document.createElement("div"), fragment = document.createDocumentFragment(), i = 0, length, childNodes;

		div.innerHTML = html;
		childNodes = div.childNodes;
		length = childNodes.length;

		for( ; i < length; i++ )
		{
			fragment.appendChild(childNodes[i].cloneNode(true));
		}

		return fragment;
	}

	pub =
	{
		markup: function( o )
		{
			return createHtml(o);
		},

		// 应用样式，与setStyle的区别在于，它可以处理Function或者cssText的情况
		applyStyles: function( el, styles )
		{

			// /////////////////////////////////////////

			// ----->>> 1!

			Ext.DomHelper.applyStyles(el,
			{
				background: 'red',
				border: '1px solid #aaa'
			});

			// ----->>> 2!

			Ext.DomHelper.applyStyles(el, 'background:red;border:1px solid #aaa;float:left;font-size:12px;');

			// ----->>> 3!

			Ext.DomHelper.applyStyles(el, function()
			{
				var ret =
				{
					background: 'red',
					border: '1px solid #aaa'
				};

				return ret;
			});

			// /////////////////////////////////////////
			if( styles )
			{
				var matches;

				el = Ext.fly(el);

				// 如果是个函数，那么取其return值，第三种情况
				if( typeof styles == "function" )
				{
					styles = styles.call();
				}

				// 处理第二种情况
				if( typeof styles == "string" )
				{
					cssRe.lastIndex = 0;
					while((matches = cssRe.exec(styles)))
					{
						el.setStyle(matches[1], matches[2]);
					}
				}

				// 如果是个对象，调用setStyle之，第一种情况
				else if( typeof styles == "object" )
				{
					el.setStyle(styles);
				}
			}
		},
		insertHtml: function( where, el, html )
		{
			var hash = {}, hashVal, range, rangeEl, setStart, frag, rs;

			// 4种位置------->>>>>> afterbegin,afterend,beforebegin,beforeend
			where = where.toLowerCase();
			// add these here because they are used in both branches of the condition.
			// IE和W3C都用这个逻辑
			hash[beforebegin] =
			[
			    'BeforeBegin', 'previousSibling'
			];
			hash[afterend] =
			[
			    'AfterEnd', 'nextSibling'
			];

			if( el.insertAdjacentHTML ) // IE
			{
				if( tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)) ) // 对table标签要特殊处理
				{
					return rs;
				}
				// add these two to the hash.
				hash[afterbegin] =
				[
				    'AfterBegin', 'firstChild'
				];
				hash[beforeend] =
				[
				    'BeforeEnd', 'lastChild'
				];
				if( (hashVal = hash[where]) )
				{
					el.insertAdjacentHTML(hashVal[0], html); // 在不同的位置插入html
					return el[hashVal[1]];
				}
			}
			else
			{ // W3C
				range = el.ownerDocument.createRange(); // ownerDocument获得当前页面的document对象
				setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
				if( hash[where] )
				{
					range[setStart](el);
					if( !range.createContextualFragment )
					{
						frag = createContextualFragment(html);
					}
					else
					{
						frag = range.createContextualFragment(html);
					}
					el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
					return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
				}
				else
				{
					rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
					if( el.firstChild )
					{
						range[setStart](el[rangeEl]);
						if( !range.createContextualFragment )
						{
							frag = createContextualFragment(html);
						}
						else
						{
							frag = range.createContextualFragment(html);
						}
						if( where == afterbegin )
						{
							el.insertBefore(frag, el.firstChild);
						}
						else
						{
							el.appendChild(frag);
						}
					}
					else
					{
						el.innerHTML = html;
					}
					return el[rangeEl];
				}
			}
			throw 'Illegal insertion point -> "' + where + '"';
		},

		insertBefore: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, beforebegin);
		},

		insertAfter: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, afterend, 'nextSibling');
		},

		insertFirst: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, afterbegin, 'firstChild');
		},

		append: function( el, o, returnElement )
		{
			return doInsert(el, o, returnElement, beforeend, '', true);
		},

		overwrite: function( el, o, returnElement )
		{
			el = Ext.getDom(el);
			el.innerHTML = createHtml(o);
			return returnElement ? Ext.get(el.firstChild) : el.firstChild;
		},

		createHtml: createHtml
	};
	return pub;
}();
